import 'package:vector_math/vector_math.dart';
import 'package:vector_math_test/src/test_utils.dart';

import '../common/test_page.dart';

class ColorsTestPage extends TestPage{
  ColorsTestPage(super.title) {
    group('Colors', () {
      test('Colors.fromRgba', testFromRgba);
      test('Colors.fromHexString', testHexString);
      test('Colors.toGrayscale', testToGrayscale);
      test('Colors.alphaBlend', testAlphaBlend);
      test('Colors.linearToGamma', testLinearGamma);
      test('Colors.rgbToHsl', testRgbHsl);
      test('Colors.rgbToHsv', testRgbHsv);
    });
  }

  void testToGrayscale() {
    final input = Vector4(0.0, 1.0, 0.5, 1.0);
    final output = input.clone();

    Colors.toGrayscale(output, output);

    relativeTest(output.r, 0.745);
    relativeTest(output.g, 0.745);
    relativeTest(output.b, 0.745);
    expect(output.a, 1.0);
  }

  void testHexString() {
    final color = Vector4.zero();

    Colors.fromHexString('#6495ED', color);

    relativeTest(color.r, 0.3921);
    relativeTest(color.g, 0.5843);
    relativeTest(color.b, 0.9294);
    relativeTest(color.a, 1.0);

    expect(Colors.toHexString(color), '6495ed');

    Colors.fromHexString('#6495eD', color);

    relativeTest(color.r, 0.3921);
    relativeTest(color.g, 0.5843);
    relativeTest(color.b, 0.9294);
    relativeTest(color.a, 1.0);

    expect(Colors.toHexString(color), '6495ed');

    Colors.fromHexString('6495eD', color);

    relativeTest(color.r, 0.3921);
    relativeTest(color.g, 0.5843);
    relativeTest(color.b, 0.9294);
    relativeTest(color.a, 1.0);

    expect(Colors.toHexString(color), '6495ed');

    Colors.fromHexString('#F0F', color);

    relativeTest(color.r, 1.0);
    relativeTest(color.g, 0.0);
    relativeTest(color.b, 1.0);
    relativeTest(color.a, 1.0);

    expect(Colors.toHexString(color), 'ff00ff');

    Colors.fromHexString('#88FF00fF', color);

    relativeTest(color.r, 1.0);
    relativeTest(color.g, 0.0);
    relativeTest(color.b, 1.0);
    relativeTest(color.a, 0.5333);

    expect(Colors.toHexString(color, alpha: true), '88ff00ff');

    Colors.fromHexString('#8F0f', color);

    relativeTest(color.r, 1.0);
    relativeTest(color.g, 0.0);
    relativeTest(color.b, 1.0);
    relativeTest(color.a, 0.5333);

    expect(Colors.toHexString(color, alpha: true), '88ff00ff');

    Colors.fromHexString('#8F0f', color);

    relativeTest(color.r, 1.0);
    relativeTest(color.g, 0.0);
    relativeTest(color.b, 1.0);
    relativeTest(color.a, 0.5333);

    expect(Colors.toHexString(color, alpha: true), '88ff00ff');

    Colors.fromHexString('#8F0f', color);

    relativeTest(color.r, 1.0);
    relativeTest(color.g, 0.0);
    relativeTest(color.b, 1.0);
    relativeTest(color.a, 0.5333);

    expect(Colors.toHexString(color, alpha: true, short: true), '8f0f');

    Colors.fromHexString('#00FF00', color);

    relativeTest(color.r, 0.0);
    relativeTest(color.g, 1.0);
    relativeTest(color.b, 0.0);
    relativeTest(color.a, 1.0);

    expect(Colors.toHexString(color, short: true), '0f0');

    Colors.fromHexString('#00FF00', color);

    relativeTest(color.r, 0.0);
    relativeTest(color.g, 1.0);
    relativeTest(color.b, 0.0);
    relativeTest(color.a, 1.0);

    expect(Colors.toHexString(color), '00ff00');

    Colors.fromHexString('#00000000', color);

    relativeTest(color.r, 0.0);
    relativeTest(color.g, 0.0);
    relativeTest(color.b, 0.0);
    relativeTest(color.a, 0.0);

    expect(Colors.toHexString(color, alpha: true), '00000000');

    // expect(testModel, object)(object)(() => Colors.fromHexString('vector_math rules!', color),
    //     throwsA(isA<FormatException>()));
  }

  void testFromRgba() {
    final output = Vector4.zero();

    Colors.fromRgba(100, 149, 237, 255, output);

    relativeTest(output.r, 0.3921);
    relativeTest(output.g, 0.5843);
    relativeTest(output.b, 0.9294);
    expect(output.a, 1.0);
  }

  void testAlphaBlend() {
    final output = Vector4.zero();
    final foreground1 = Vector4(0.3921, 0.5843, 0.9294, 1.0);
    final foreground2 = Vector4(0.3921, 0.5843, 0.9294, 0.5);
    final background1 = Vector4(1.0, 0.0, 0.0, 1.0);
    final background2 = Vector4(1.0, 0.5, 0.0, 0.5);

    output.setFrom(foreground1);
    Colors.alphaBlend(output, background1, output);

    relativeTest(output.r, 0.3921);
    relativeTest(output.g, 0.5843);
    relativeTest(output.b, 0.9294);
    expect(output.a, 1.0);

    output.setFrom(background2);
    Colors.alphaBlend(foreground1, output, output);

    relativeTest(output.r, 0.3921);
    relativeTest(output.g, 0.5843);
    relativeTest(output.b, 0.9294);
    expect(output.a, 1.0);

    Colors.alphaBlend(foreground2, background1, output);

    relativeTest(output.r, 0.6960);
    relativeTest(output.g, 0.2921);
    relativeTest(output.b, 0.4647);
    expect(output.a, 1.0);

    Colors.alphaBlend(foreground2, background2, output);

    relativeTest(output.r, 0.5947);
    relativeTest(output.g, 0.5561);
    relativeTest(output.b, 0.6195);
    expect(output.a, 0.75);
  }

  void testLinearGamma() {
    final gamma = Vector4.zero();
    final linear = Vector4.zero();
    final foreground = Vector4(0.3921, 0.5843, 0.9294, 1.0);

    gamma.setFrom(foreground);
    Colors.linearToGamma(gamma, gamma);

    relativeTest(gamma.r, 0.6534);
    relativeTest(gamma.g, 0.7832);
    relativeTest(gamma.b, 0.9672);
    expect(gamma.a, foreground.a);

    linear.setFrom(gamma);
    Colors.gammaToLinear(linear, linear);

    relativeTest(linear.r, foreground.r);
    relativeTest(linear.g, foreground.g);
    relativeTest(linear.b, foreground.b);
    expect(linear.a, foreground.a);
  }

  void testRgbHsl() {
    final hsl = Vector4.zero();
    final rgb = Vector4.zero();
    final input = Vector4(0.3921, 0.5843, 0.9294, 1.0);

    hsl.setFrom(input);
    Colors.rgbToHsl(hsl, hsl);

    relativeTest(hsl.x, 0.6070);
    relativeTest(hsl.y, 0.7920);
    relativeTest(hsl.z, 0.6607);
    expect(hsl.a, input.a);

    rgb.setFrom(hsl);
    Colors.hslToRgb(rgb, rgb);

    relativeTest(rgb.r, input.r);
    relativeTest(rgb.g, input.g);
    relativeTest(rgb.b, input.b);
    expect(rgb.a, input.a);

    void testRoundtrip(Vector4 input) {
      final result = input.clone();

      Colors.rgbToHsl(result, result);
      Colors.hslToRgb(result, result);

      absoluteTest(result.r, input.r);
      absoluteTest(result.g, input.g);
      absoluteTest(result.b, input.b);
      expect(result.a, input.a);
    }

    testRoundtrip(Colors.red);
    testRoundtrip(Colors.green);
    testRoundtrip(Colors.blue);
    testRoundtrip(Colors.black);
    testRoundtrip(Colors.white);
    testRoundtrip(Colors.gray);
    testRoundtrip(Colors.yellow);
    testRoundtrip(Colors.fuchsia);
  }

  void testRgbHsv() {
    final hsv = Vector4.zero();
    final rgb = Vector4.zero();
    final input = Vector4(0.3921, 0.5843, 0.9294, 1.0);

    hsv.setFrom(input);
    Colors.rgbToHsv(hsv, hsv);

    relativeTest(hsv.x, 0.6070);
    relativeTest(hsv.y, 0.5781);
    relativeTest(hsv.z, 0.9294);
    expect(hsv.a, input.a);

    rgb.setFrom(hsv);
    Colors.hsvToRgb(rgb, rgb);

    relativeTest(rgb.r, input.r);
    relativeTest(rgb.g, input.g);
    relativeTest(rgb.b, input.b);
    expect(rgb.a, input.a);

    void testRoundtrip(Vector4 input) {
      final result = input.clone();

      Colors.rgbToHsv(result, result);
      Colors.hsvToRgb(result, result);

      absoluteTest(result.r, input.r);
      absoluteTest(result.g, input.g);
      absoluteTest(result.b, input.b);
      expect(result.a, input.a);
    }

    testRoundtrip(Colors.red);
    testRoundtrip(Colors.green);
    testRoundtrip(Colors.blue);
    testRoundtrip(Colors.black);
    testRoundtrip(Colors.white);
    testRoundtrip(Colors.gray);
    testRoundtrip(Colors.yellow);
    testRoundtrip(Colors.fuchsia);
  }

}